﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PaperRenderingInterfaces;
using System.ComponentModel.Composition;
using HtmlAgilityPack;
using PaperPluginUtilities;
using DeepZoomPivotConstructor.PivotLib;

namespace DZEROPhysicsResultsPages
{
    /// <summary>
    /// The top level DZERO pages are tables of links to the actual conf note info...
    /// This guy will parse one of those pages and fob-off the image processing on the next
    /// guy down.
    /// </summary>
    [Export(typeof(IPaperRender))]
    [PaperRender("DZEROMasterPhysicsGroupPage")]
    public class ScanMasterPage : IPaperRender
    {
        /// <summary>
        /// Access the web as we need.
        /// </summary>
        [Import(typeof(IWebAccess))]
        IWebAccess WebGetter;

        /// <summary>
        /// So we can do the rendering of the notes we find.
        /// </summary>
        [Import]
        IPaperRenderEngine MyPaperRenderEngine;

        /// <summary>
        /// Given the URI of what we are looking for, find the
        /// list of links!
        /// </summary>
        /// <param name="renderAddress"></param>
        /// <returns></returns>
        public IEnumerable<PivotImage> Render(string renderAddress)
        {
            ///
            /// First, get the html back
            /// 

            string html = WebGetter.GetUriAsString(new Uri(renderAddress));
            HtmlDocument doc = new HtmlDocument();
            doc.LoadHtml(html);

            ///
            /// Calculate the base URI here
            /// 

            string[] uriSplit = renderAddress.Split('/');
            int toTake = uriSplit.Length - 1;
            Uri baseUri;
            baseUri = new Uri(renderAddress);

            ///
            /// Loop over all the tables in here!
            /// 

            var images = new EnumerableWrapper<HtmlNode>(doc.DocumentNode.SelectNodes("//table"))
                    .SelectMany(i => FindNotesInTable(i, baseUri));

            return images;

        }

        /// <summary>
        /// We are looking at a single table. See if we can't grab all the notes from within it.
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private IEnumerable<PivotImage> FindNotesInTable(HtmlNode node, Uri baseUri)
        {
            /// Fix up the table first

            var tableNode = node.FixUpTableHtml();

            var images = tableNode.ScanSubNodes("tr").SelectMany(i => FindNotesInTableRow(i, baseUri));

            return images;
        }

        /// <summary>
        /// Finds a DZERO note reference in a single table.
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private IEnumerable<PivotImage> FindNotesInTableRow(HtmlNode node, Uri baseUri)
        {
            var images = node.ScanSubNodes("td").SelectMany(i=> FindNoteInCell(i, baseUri));
            return images;
        }

        /// <summary>
        /// Helper to keep track of link info
        /// </summary>
        private struct LinkInfo
        {
            public string url;
            public string urlName;
        }

        /// <summary>
        /// Look in a particular cell for the info we need.
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private IEnumerable<PivotImage> FindNoteInCell(HtmlNode node, Uri baseUri)
        {
            ///
            /// Find all the links we can. If we find two links pointing to the same
            /// thing, then we should combine them (this is more bad html authorship).
            /// 

            List<LinkInfo> links = new List<LinkInfo>();
            node.ScanSubNodes("a").Execute(linkNode =>
            {
                LinkInfo info;
                var hrefAttr = linkNode.Attributes["href"];
                if (hrefAttr != null)
                {
                    info.url = hrefAttr.Value;
                    info.urlName = linkNode.InnerText.CleanHTMLText();

                    var oldLink = (from l in links where l.url == info.url select l).FirstOrDefault();
                    if (oldLink.url != null)
                    {
                        links.Remove(oldLink);
                        oldLink.urlName += " " + info.urlName;
                        links.Add(oldLink);
                    }
                    else
                    {
                        links.Add(info);
                    }
                }
            });

            ///
            /// There should be 1 or two links, depending on what is going on...
            /// 

            if (links.Count == 0)
            {
                return Enumerable.Empty<PivotImage>();
            }

            ///
            /// ok - so we want the link that goes to the images. We make the assumption
            /// that the first link on the line is the note name, and other links (which might lead
            /// to real figures, etc.) are not the note name.
            /// 

            string title = "";
            var allImages = links.SelectMany(l =>
            {
                if (title == "")
                {
                    title = l.urlName;
                }
                if (l.url.Split('/').Last().Contains('.') || l.urlName.Length == 0)
                {
                    return Enumerable.Empty<PivotImage>();
                }

                if (!l.url.EndsWith("/"))
                {
                    l.url += "/";
                }

                Uri noteSubPage = new Uri(baseUri, l.url);

                if (!noteSubPage.OriginalString.StartsWith("http://www-d0.fnal.gov/Run2Physics/WWW/results/prelim"))
                {
                    return Enumerable.Empty<PivotImage>();
                }

                return MyPaperRenderEngine.Render("DZERONotePage", noteSubPage.OriginalString)
                    .Apply(i => i.Add("More Information", "Note Plot Page", new Uri(baseUri, l.url)))
                    .Apply(i => i.Add("Note Title", title))
                    .Apply(i =>
                    {
                        if (i.Description == null || i.Description.Length == 0)
                        {
                            i.Description = "From the note titled " + title;
                        }
                    });
            });

            return allImages;
        }
    }
}
